
#include <sys/ioctl.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/io.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include "drv_pcie.h"

uint32 g_fd;
void Read_FPGA_VER() {
    int vernum;
    int ret = ioctl(g_fd, FPGAVERSION, &vernum);
    if (ret != 0) {
        LOG_ERROR("#ERR: -Read_FPGA_VER- error to read fpga version, errcode %d \n", ret);
    }
}

int Read_Chan_NUM() {
    uint8 channum;
    int ret = ioctl(g_fd, ID_NUM, &channum);
    if (ret != 0) {
        LOG_ERROR("#ERR: -Read_Chan_NUM- error to read chan number ERROR = %d\n", ret);
        return KT_ERROR;
    }
    return channum;
}

void tOpen() {
    char fileName[32];
    sprintf(fileName, "/dev/xbmd");
    g_fd = open(fileName, O_RDWR);
    if (g_fd < 0) {
        LOG_ERROR("#ERR: error to open %s \n", fileName);
    } else {
        LOG_INFO("open %s OK\n", fileName);
    }
}

int Read_USER_DMA_Status() {
    int Status;
    int ret = ioctl(g_fd, DMASTATUS, &Status);
    if (ret != 0) {
        LOG_ERROR("#ERR: -Read_USER_DMA_Status- read dma status, errcode %d \n", ret);
    }
}

// void tRecv() {
//     unsigned char buf[DATA_BUFF_SIZE + 1];
//     int ret = read(g_fd, (void *)&buf, sizeof(buf));
//     if (ret == 0) {

//     } else {
//         LOG_ERROR("#ERR: -tRecv- recv errcode %d \n", ret);
//     }
// }

void tInit() {
    unsigned int io;
    int ret;
    ret = ioctl(g_fd, WRWDMATLPS, PCIE_BUFF_SIZE);
    if (ret != 0) {
       LOG_ERROR("#ERR: error to write dma tlp size errcode %d \n", ret);
    }
    Read_FPGA_VER();
    LOG_INFO("tInit finished\n");
}

int tDMAStart() {
    int start = 0x01;
    int mode = 0x01;
    // config dma work mode , bit0=1 时表示板卡DMA写操作,  bit0=0 时表示板卡DMA读操作
    int ret = ioctl(g_fd, WRDDMACR, mode);
    if (ret != 0) {
        LOG_ERROR("#ERR: -tDMAStart- error to config DMAMode, errcode is = %d\n", ret);
        return KT_ERROR;
    }

    //DMA Command lock,Start DMA,  bit0=1 时命令锁
    ret = ioctl(g_fd, WRDDMAST, start);
    if (ret != 0) {
        LOG_ERROR("#ERR: -tDMAStart- error command unlocked, errcode is = %d\n", ret);
        return KT_ERROR;
    }
    return KT_OK;
}

int Disable_DMA_Trans() {
    //USR_DMA_END _IOW(XBMD_CTL_TYPE,0x15, unsigned int) 2
    int ret = ioctl(g_fd, USR_DMA_END, DIS_DMA_TRANS);
    if (ret == 0) {
        LOG_INFO("USER Disable DMA Transfer OK \n");
        return KT_OK;
    } else {
        LOG_ERROR("#ERR: -Disable_DMA_Trans- error to Disable DMA_Transfer, errcode %d \n", ret);
        return KT_ERROR;
    }
}

int Read_DMA_STATUS() {
    int Status;
    int ret = ioctl(g_fd, DMASTATUS, &Status);
    if (ret != 0){
        LOG_ERROR("USER Disable DMA Transfer ERROR = %d\n", ret);
        return KT_ERROR;
    }
    return Status;
}

int Read_DMAWR_CLKNUM() {

    int ret;
    int clknum;

    ret = ioctl(g_fd, RDDMAWRTLPCLKN, &clknum);
    if (ret == 0) {
        LOG_DEBUG("READ DMA WRTIE TLP CLK NUMBER  = %d\n", clknum);
        return clknum;
    } else {
        LOG_INFO("#ERR: -Read_DMAWR_CLKNUM-  error to read and write DMA, errcode %d\n", ret);
        return ret;
    }
}

int Read_DMARD_CLKNUM() {
    int ret;
    int clknum;

    ret = ioctl(g_fd, DMARD_CLKNUM_RDREG, &clknum);
    if (ret == 0) {
        printf("READ DMA READ TLP CLK NUMBER  = %d\n", clknum);
    } else {
        printf("READ DMA READ TLP CLK NUMBER ERROR = %d\n", ret);
        //return  ret;
    }
    return clknum;
}

int tUpdateID() {
    int ret = ioctl(g_fd, USR_ID_UP, 0x55);
    if ( ret != 0 ) {
        LOG_ERROR("#ERR: -tUpdateID- update ID ERROR, errcode: %d \n", ret);
        return KT_ERROR;
    }
    return ret;
}

int tDMAStop() {
    int cnt = 0;
    int bit, temp;
    if(Disable_DMA_Trans() == KT_ERROR) return KT_ERROR;
    // do {
    //     if (cnt++ == 1000) {
    //         LOG_ERROR("#ERR: -tDMAStop- error to disable DMA Transfer failure \n");
    //         return KT_ERROR;
    //     }
    //     if((temp = Read_DMA_STATUS()) == KT_ERROR) return KT_ERROR;
    //     bit = temp & 0x20;
    // } while (bit != 0x20);
    return KT_OK;
}
void init_pcie() {
    tOpen();
    tInit();
}

extern int thread_recv_pcie_signal;
/**
 * @param buff 需要接收数据的缓存区 @param len 缓冲区的长度
 */ 
int get_pcieData(uint8 *buff, long len)
{

#ifdef     IF_NOEXIT_PCIE
    memset(buff, 0xAA, len);
    buff[0] = 0xAA;
    // while(1) {
        if(!thread_recv_pcie_signal) {
            return KT_WARN;  //如果外界干扰结束的话, 不对数据做保存
        }
        // usleep(100*1000); 
    // }
#endif  //IF_EXIT_PCIE

#ifndef      IF_NOEXIT_PCIE
    if(tUpdateID() == KT_ERROR) return KT_ERROR;
    if(tDMAStart() == KT_ERROR) return KT_ERROR;
    
    int kt_code = 0;
    while ((kt_code = Read_Chan_NUM()) == 0x55) {
        // 在数据传输过程中如果 被上层应用打断之后需要发送结束命令
        if(kt_code == KT_ERROR) return KT_ERROR;
        if(!thread_recv_pcie_signal) {
            if(tDMAStop() == KT_ERROR) return KT_ERROR;
            return KT_WARN;  //如果外界干扰结束的话, 不对数据做保存
        }
    }
    //接收到中断如果不为 0x55的时候, 将数据拷贝到 buff 中
    read(g_fd, (void *)buff, len);
    return kt_code;
#endif //IF_EXIT_PCIE
}
